/**
 * 
 */
package org.kad.gwt.web.client.kademelia;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

import org.kad.gwt.web.client.kademelia.model.KadNode;
import org.kad.gwt.web.client.kademelia.model.rpc.KadRpcMessage;
import org.kad.gwt.web.client.kademelia.model.rpc.ping.KadRpcPingRequest;
import org.kad.gwt.web.client.kademelia.model.rpc.store.KadRpcStoreRequest;
import org.kad.gwt.web.client.kademelia.rpc.ping.mvp.HasKadPingHandlers;
import org.kad.gwt.web.client.kademelia.rpc.ping.mvp.KadPingEvent;
import org.kad.gwt.web.client.kademelia.rpc.store.mvp.HasKadStoreHandlers;
import org.kad.gwt.web.client.kademelia.rpc.store.mvp.KadStoreEvent;
import org.kad.gwt.web.client.kademelia.transport.mvp.KadRequestEvent;
import org.kad.gwt.web.client.mvp.AbstractHasHandlers;

import com.google.gwt.event.shared.EventBus;

/**
 * The kad main service.
 * 
 * @author Pierrick HYMBERT &lt;pierrick [dot] hymbert [at] gmail [dot] com&gt;
 */
@Singleton
public class KadService extends AbstractHasHandlers implements KadRequestEvent.Handler, HasKadPingHandlers, HasKadStoreHandlers {
    /**
     * 
     */
    private final Provider<KadNode> localNode;

    /**
     * @param transportServiceIn
     */
    @Inject
    private KadService(final EventBus eventBus, Provider<KadNode> localNodeIn) {
        super(eventBus);
        this.localNode = localNodeIn;
        eventBus.addHandler(KadRequestEvent.getType(), this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onKadRequest(final KadRequestEvent event) {
        KadRpcMessage request = event.getRequest();
        if (isTargetedForLocalNode(request)) {
            switch (event.getRequest().getType()) {
            case PING:
                handlePing(event);
                break;
            case STORE:
                handleStore(event);
                break;
            // FIXME
            }
        }
    }

    /**
     * Create and dispatch a ping event
     * 
     * @param event
     *            The kad request event
     */
    private void handlePing(final KadRequestEvent event) {
        KadPingEvent pingEvent = KadPingEvent.fire(this, (KadRpcPingRequest) event.getRequest());
        event.setResponse(pingEvent.getPongResponse());
    }

    /**
     * Create and dispatch a store event
     * 
     * @param event
     *            The kad request event
     */
    private void handleStore(final KadRequestEvent event) {
        KadStoreEvent storeEvent = KadStoreEvent.fire(this, (KadRpcStoreRequest) event.getRequest());
        event.setResponse(storeEvent.getStoreResponse());
    }

    /**
     * Check if this message is targeted to this local node.
     * 
     * @param message
     *            The message to check
     * @return True if this message is targeted to the local node, false otherwise
     */
    private boolean isTargetedForLocalNode(KadRpcMessage message) {
        return localNode.get().equals(message.getTarget());
    }
}
